package com.jinlia.show.modules.system.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jinlia.show.common.core.exception.MyRuntimeException;
import com.jinlia.show.modules.base.constant.EnableStatusEnum;
import com.jinlia.show.modules.base.model.po.GoodsAttrPO;
import com.jinlia.show.modules.base.model.query.GoodsQuery;
import com.jinlia.show.modules.base.system.entity.*;
import com.jinlia.show.modules.base.model.form.GoodsForm;
import com.jinlia.show.modules.base.model.po.GoodsPO;
import com.jinlia.show.modules.base.system.service.*;
import com.jinlia.show.modules.system.model.vo.excel.ExcelGoodsVO2;
import com.jinlia.show.modules.system.service.ifc.IGoodsService;
import com.jinlia.show.modules.system.utils.EasyExcelWarp;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
public class GoodsService extends GoodsMapperService implements IGoodsService {

    @Autowired
    GoodsAttrMapperService goodsAttrMapperService;
    @Autowired
    GoodsAttrValueMapperService goodsAttrValueMapperService;
    @Autowired
    GoodsTypeMapperService goodsTypeMapperService;
    @Autowired
    GoodsLabelMapperService goodsTagMapperService;
    @Autowired
    GoodsLabelRelMapperService goodsTagRelMapperService;


    public List<GoodsPO> getForOrder(GoodsForm goodsRequest) {
        List<GoodsPO> forOrder = this.baseMapper.getVOList(goodsRequest);
        return forOrder;
    }

    /**
     * 批量添加物料
     *
     * @param goodsVOS
     */
    private void addByGoodsVOs(List<GoodsPO> goodsVOS) {
        for (GoodsPO goodsVO : goodsVOS) {
            //商品
            Goods goods = GoodsPO.toEntity(goodsVO);
            //校验商品名称(唯一性)
            List<Goods> list = this.lambdaQuery().eq(Goods::getGoodsName, goods.getGoodsName()).list();
            if (list.size() > 1) {
                throw new RuntimeException(String.format("商品名已存在:%S", goods.getGoodsName()));
            } else if (list.size() == 1 && !list.get(0).getId().equals(goodsVO.getId())) {
                throw new RuntimeException(String.format("商品名已存在:%S", goods.getGoodsName()));
            }
            this.save(goods);
            List<GoodsAttrPO> goodsAttrVOList = goodsVO.getGoodsAttrPOS();
            if (CollectionUtils.isEmpty(goodsAttrVOList)) {
                continue;
            }
            //新增商品佐料
            List<GoodsAttr> collectGoodsAttr = goodsAttrVOList.stream().map(i -> {
                GoodsAttr goodsAttr = GoodsAttrPO.toEntity(i);
                goodsAttr.setGoodsId(goods.getId());
                i.setGoodsId(goods.getId());
                return goodsAttr;
            }).collect(Collectors.toList());
            goodsAttrMapperService.saveBatch(collectGoodsAttr);
            //佐料项
            List<GoodsAttrValue> goodsAttrValues = new ArrayList<>();
            for (GoodsAttrPO goodsAttrVO : goodsAttrVOList) {
                goodsAttrVO.getGoodsAttrValues().forEach(i -> i.setAttrId(goodsAttrVO.getId()));
                goodsAttrValues.addAll(goodsAttrVO.getGoodsAttrValues());
            }
            goodsAttrValueMapperService.saveBatch(goodsAttrValues);
        }
    }

    /**
     * 更新
     *
     * @param goodsVOS
     */
    private void updateByGoodsVOs(List<GoodsPO> goodsVOS) {
        for (GoodsPO goodsVO : goodsVOS) {
            delByGoodsVOs(goodsVO);
        }
        //重新添加
        addByGoodsVOs(goodsVOS);
    }

    /**
     * 删除物料
     *
     * @param goodsVO
     */
    private void delByGoodsVOs(GoodsPO goodsVO) {
        //删除
        this.removeById(goodsVO.getId());
        //物料关联的佐料
        List<GoodsAttr> listGoodsAttr = goodsAttrMapperService.lambdaQuery()
                .in(GoodsAttr::getGoodsId, goodsVO.getId())
                .list();
        List<Long> goodsAttrIds = listGoodsAttr.stream().map(GoodsAttr::getId).collect(Collectors.toList());
        goodsAttrMapperService.removeByIds(goodsAttrIds);
        List<GoodsAttrValue> list = goodsAttrValueMapperService.lambdaQuery()
                .in(GoodsAttrValue::getAttrId, goodsAttrIds)
                .list();
        goodsAttrValueMapperService.removeByIds(list.stream().map(GoodsAttrValue::getId).collect(Collectors.toList()));

    }

    @SneakyThrows
    @Transactional
    public void importGoodsTemp2(MultipartFile file2) {
        try (Workbook workbook = new XSSFWorkbook(file2.getInputStream())) {
            Sheet sheet = workbook.getSheetAt(0);
            //获取excel表格合并的数据信息
            List<EasyExcelWarp.CellRangeAddressWarp> collect = sheet.getMergedRegions()
                    .stream()
                    .map(i -> new EasyExcelWarp.CellRangeAddressWarp(i))
                    .collect(Collectors.toList());
            //提取excel数据到ExcelGoodsVO2
            ArrayList<ExcelGoodsVO2> list = getExcelGoodsVO2ArrayList(sheet, collect);
            //ExcelGoodsVO2 数据转GoodsPO
            ArrayList<GoodsPO> goodsPOS = getGoodsPOSByVO2(list);
            //保存数据库
            this.saveOrUpPOList(goodsPOS);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private ArrayList<GoodsPO> getGoodsPOSByVO2(ArrayList<ExcelGoodsVO2> list) {
        //商品类型和商品标签
        Map<String, GoodsLabel> mapGoodsTag = goodsTagMapperService.list().stream().collect(Collectors.toMap(GoodsLabel::getTitle, Function.identity()));
        Map<String, GoodsType> mapGoodsType = goodsTypeMapperService.list().stream().collect(Collectors.toMap(GoodsType::getName, Function.identity()));
        ArrayList<GoodsPO> goodsPOS = new ArrayList<>();
        Map<String, List<ExcelGoodsVO2>> groupingByGoodsName =
                list.stream().collect(Collectors.groupingBy(ExcelGoodsVO2::getGoodsName));//根据商品名分组
        //根据商品名->做商品的唯一值判断
        List<Goods> listExistGoods = this.lambdaQuery().in(Goods::getGoodsName, groupingByGoodsName.keySet()).list();
        //过滤掉待更新的数据
        listExistGoods = listExistGoods.stream().filter(i -> groupingByGoodsName.get(i.getGoodsName()).get(0).getGoodsId() == null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(listExistGoods)) {
            String listExistGoodsName = listExistGoods.stream().map(Goods::getGoodsName).collect(Collectors.joining(", "));
            throw new MyRuntimeException(String.format("商品名已存在(%S)", listExistGoodsName));
        }
        for (String goodsName : groupingByGoodsName.keySet()) {
            //同一个商品
            GoodsPO goodsPO = fixGoodPOAttributeByVO2(groupingByGoodsName.get(goodsName).get(0), mapGoodsTag, mapGoodsType);
            goodsPOS.add(goodsPO);

            Map<String, List<ExcelGoodsVO2>> groupingByAttr =
                    groupingByGoodsName.get(goodsName).stream().filter(i -> StringUtils.hasLength(i.getAttrName())).collect(Collectors.groupingBy(ExcelGoodsVO2::getAttrName));//根据Attr分组
            for (String Attr : groupingByAttr.keySet()) {
                //同一个商品的Attr
                GoodsAttrPO goodsAttrPO = new GoodsAttrPO();
                goodsPO.getGoodsAttrPOS().add(goodsAttrPO);
                Map<String, List<ExcelGoodsVO2>> groupingByAttrValue =
                        groupingByAttr.get(Attr).stream().collect(Collectors.groupingBy(ExcelGoodsVO2::getAttrName));//根据商品名分组
                goodsAttrPO.setGoodsAttrValues(new ArrayList<>());
                for (String AttrValue : groupingByAttrValue.keySet()) {//同一个商品的Attr的AttrValue
                    for (ExcelGoodsVO2 excelGoodsVO2 : groupingByAttrValue.get(AttrValue)) {
                        //填充属性
                        GoodsAttrValue goodsAttrValue = new GoodsAttrValue();
                        goodsAttrPO.getGoodsAttrValues().add(goodsAttrValue);
                        goodsAttrValue.setAttrValueName(excelGoodsVO2.getAttrValueName());//填充name
                        goodsAttrValue.setAttrValuePics(excelGoodsVO2.getAttrValuePics());//填充图片
                        if (StringUtils.hasLength(excelGoodsVO2.getAttrValuePrice())) {
                            goodsAttrValue.setAttrValuePrice(new BigDecimal(excelGoodsVO2.getAttrValuePrice()));//填充价格
                        }
                    }
                }
                //填充属性
                goodsAttrPO.setAttrName(groupingByAttr.get(Attr).get(0).getAttrName());
            }
        }
        return goodsPOS;
    }

    private GoodsPO fixGoodPOAttributeByVO2(ExcelGoodsVO2 vo2, Map<String, GoodsLabel> mapGoodsTag, Map<String, GoodsType> mapGoodsType) {
        GoodsPO goodsPO = new GoodsPO();
        goodsPO.setId(vo2.getGoodsId());
        goodsPO.setGoodsAttrPOS(new ArrayList<>());
        goodsPO.setGoodsName(vo2.getGoodsName());//商品名
        goodsPO.setPrice(new BigDecimal(vo2.getPrice()));//基础价格
        goodsPO.setGoodsPics(vo2.getGoodsPics());
        goodsPO.setEnableStatus(EnableStatusEnum.ENABLE.getValue());
        //商品类型
        if (!mapGoodsType.containsKey(vo2.getGoodsType())) {
            GoodsType goodsType = new GoodsType();
            goodsType.setName(vo2.getGoodsType());
            goodsTypeMapperService.save(goodsType);//回显id
            mapGoodsType.put(vo2.getGoodsType(), goodsType);
        }
        goodsPO.setGoodsType(mapGoodsType.get(vo2.getGoodsType()).getId());
        //商品标签
        String goodsTags = vo2.getGoodsTags();
        if (goodsTags != null) {
            goodsPO.setTags(new ArrayList<>());
            String[] split = goodsTags.replaceAll("，", ",").split(",");
            for (String s : split) {
                if (!mapGoodsTag.containsKey(s)) {
                    GoodsLabel goodsTag = new GoodsLabel();
                    goodsTag.setTitle(s);
                    goodsTagMapperService.save(goodsTag);
                    mapGoodsTag.put(s, goodsTag);
                }
                goodsPO.getTags().add(mapGoodsTag.get(s));
            }
        }
        return goodsPO;
    }

    private ArrayList<ExcelGoodsVO2> getExcelGoodsVO2ArrayList(Sheet sheet, List<EasyExcelWarp.CellRangeAddressWarp> collect) {
        //商品id0, 商品名1,商品类型2,价格3,商品标签4,Attr名5,AttrValue名6,AttrValue价格7。  (表头)
        ArrayList<ExcelGoodsVO2> list = new ArrayList<>();
        for (int iRow = 0; iRow <= sheet.getLastRowNum(); iRow++) {
            Row  row = sheet.getRow(iRow);
            if (row.getRowNum() == 0) {
                continue;
            }
            String[] per = new String[10];
            //id,商品名,商品类型,商品价格,商品图片,商品标签,Attr名,AttrValue名,AttrValue价格,AttrValue图片
            for (int iCol = 0; iCol < 10; iCol++) {
                Cell cell = row.getCell(iCol);
                if (cell == null) {//合并的单元格
                    for (int i = 0; i < collect.size(); i++) {
                        EasyExcelWarp.CellRangeAddressWarp  cellRangeAddressWarp = collect.get(i);
                        if (iRow >= cellRangeAddressWarp.getFirstRow() && iRow <= cellRangeAddressWarp.getLastRow()){
                            if (iCol >= cellRangeAddressWarp.getFirstCol() && iCol <= cellRangeAddressWarp.getLastCol()){
                                if (StringUtils.hasLength(cellRangeAddressWarp.getCellValue())) {
                                    per[iCol] = cellRangeAddressWarp.getCellValue();
                                }
                                continue;
                            }
                        }
                    }
                    continue;
                }
                EasyExcelWarp.CellRangeAddressWarp inMergeRange = EasyExcelWarp.isInMergeRange(collect, cell);
                if (inMergeRange != null) {//是否为合并行
                    if (StringUtils.hasLength(inMergeRange.getCellValue())) {
                        per[iCol] = inMergeRange.getCellValue();
                    }
                } else {
                    if (StringUtils.hasLength(EasyExcelWarp.getCellValueAsString(cell))) {
                        per[iCol] = EasyExcelWarp.getCellValueAsString(cell);
                    }
                }
            }
            list.add(new ExcelGoodsVO2(per));
        }
        return list;
    }

    public void exportGoods2(GoodsQuery goodsQuery, HttpServletResponse response) {
        //商品
        List<Goods> list = this.lambdaQuery()
                .eq(Objects.nonNull(goodsQuery.getGoodsId()), Goods::getId, goodsQuery.getGoodsId())
                .orderByDesc(Goods::getId)
                .list();
        //填充Attr
        List<GoodsPO> goodsVOs = list.stream().map(GoodsPO::fromEntity).collect(Collectors.toList());
        Map<Long, List<GoodsAttrPO>> collect = goodsAttrMapperService.getPOsByGoodsId(list.stream().map(Goods::getId).toArray(Long[]::new)).stream()
                .collect(Collectors.groupingBy(GoodsAttr::getGoodsId));
        //填充tag
        for (GoodsPO goodsVO : goodsVOs) {
            goodsVO.setTags(goodsTagMapperService.getGoodsTagsByGoodsId(goodsVO.getId()));
            goodsVO.setGoodsAttrPOS(collect.get(goodsVO.getId()));
        }
        //商品类型
        Map<Long, String> goodsTypeMap = goodsTypeMapperService.list().stream()
                .collect(Collectors.toMap(GoodsType::getId, GoodsType::getName));
        ArrayList<ExcelGoodsVO2> list1 = new ArrayList<>();
        /**
         * 导出报表
         */
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-disposition", String.format("attachment; filename=%s", new String("批量导出商品".getBytes())));
        try (
                InputStream is = getClass().getResourceAsStream("/templates/goods-temp.xlsx");
                XSSFWorkbook wb = new XSSFWorkbook(is)) {
            XSSFSheet sheet = wb.getSheetAt(0);
            //                       商品名	       商品类型	    价格	        商品图片	      商品标签	  Attr名	  AttrValue名	   AttrValue价格	    AttrValue图片
            String[] goodsAttrs = {"goodsId", "goodsName", "goodsType", "price", "goodsPics", "goodsTags", "attrName", "attrValueName", "attrValuePrice", "attrValuePics"};
            for (int i = 0; i < goodsVOs.size(); i++) {//商品名
                if (CollectionUtils.isEmpty(goodsVOs.get(i).getGoodsAttrPOS())) {
                    //没有规格参数的
                    ExcelGoodsVO2 excelGoodsVO2 = new ExcelGoodsVO2();
                    excelGoodsVO2.setGoodsName(goodsVOs.get(i).getGoodsName());
                    excelGoodsVO2.setGoodsType(goodsTypeMap.get(goodsVOs.get(i).getGoodsType()));
                    excelGoodsVO2.setPrice(Objects.isNull(goodsVOs.get(i).getPrice()) ? "" :
                            goodsVOs.get(i).getPrice().toString());
                    excelGoodsVO2.setGoodsPics(goodsVOs.get(i).getGoodsPics());
                    excelGoodsVO2.setGoodsTags(Objects.isNull(goodsVOs.get(i).getTags()) ? "" :
                            goodsVOs.get(i).getTags().stream().map(GoodsLabel::getTitle).collect(Collectors.joining(",")));
                    excelGoodsVO2.setAttrName("");
                    excelGoodsVO2.setAttrValueName("");
                    excelGoodsVO2.setAttrValuePrice("");
                    excelGoodsVO2.setAttrValuePics("");
                    //
                    excelGoodsVO2.setGoodsId(goodsVOs.get(i).getId());//设置商品id
                    excelGoodsVO2.setAttrId(0l); //没有属性设置默认值
                    list1.add(excelGoodsVO2);
                } else {
                    for (int i1 = 0; i1 < goodsVOs.get(i).getGoodsAttrPOS().size(); i1++) {//Attr
                        List<GoodsAttrValue> goodsAttrValues = goodsVOs.get(i).getGoodsAttrPOS().get(i1).getGoodsAttrValues();//AttrValue
                        if (CollectionUtils.isEmpty(goodsAttrValues)) {
                            //没有AttrValue
                            ExcelGoodsVO2 excelGoodsVO2 = new ExcelGoodsVO2();
                            excelGoodsVO2.setGoodsName(goodsVOs.get(i).getGoodsName());
                            excelGoodsVO2.setGoodsType(goodsTypeMap.get(goodsVOs.get(i).getGoodsType()));
                            excelGoodsVO2.setPrice(Objects.isNull(goodsVOs.get(i).getPrice()) ? "" :
                                    goodsVOs.get(i).getPrice().toString());
                            excelGoodsVO2.setGoodsPics(goodsVOs.get(i).getGoodsPics());
                            excelGoodsVO2.setGoodsTags(Objects.isNull(goodsVOs.get(i).getTags()) ? "" :
                                    goodsVOs.get(i).getTags().stream().map(GoodsLabel::getTitle).collect(Collectors.joining(",")));
                            excelGoodsVO2.setAttrName(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getAttrName());
                            excelGoodsVO2.setAttrValueName("");
                            excelGoodsVO2.setAttrValuePrice("");
                            excelGoodsVO2.setAttrValuePics("");
                            excelGoodsVO2.setGoodsId(goodsVOs.get(i).getId());
                            excelGoodsVO2.setAttrId(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getId());
                            list1.add(excelGoodsVO2);

                        } else
                            for (int i2 = 0; i2 < goodsAttrValues.size(); i2++) {
                                //表头 : 商品名0,商品类型1,价格2,商品标签3,Attr名4,AttrValue名5,AttrValue价格6。  (表头)
                                ExcelGoodsVO2 excelGoodsVO2 = new ExcelGoodsVO2();
                                excelGoodsVO2.setGoodsName(goodsVOs.get(i).getGoodsName());
                                excelGoodsVO2.setGoodsType(goodsTypeMap.get(goodsVOs.get(i).getGoodsType()));
                                excelGoodsVO2.setPrice(Objects.isNull(goodsVOs.get(i).getPrice()) ? "" :
                                        goodsVOs.get(i).getPrice().toString());
                                excelGoodsVO2.setGoodsPics(goodsVOs.get(i).getGoodsPics());
                                excelGoodsVO2.setGoodsTags(Objects.isNull(goodsVOs.get(i).getTags()) ? "" :
                                        goodsVOs.get(i).getTags().stream().map(GoodsLabel::getTitle).collect(Collectors.joining(",")));
                                excelGoodsVO2.setAttrName(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getAttrName());
                                excelGoodsVO2.setAttrValueName(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getGoodsAttrValues().get(i2).getAttrValueName());
                                excelGoodsVO2.setAttrValuePrice(Objects.isNull(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getGoodsAttrValues().get(i2).getAttrValuePrice()) ? "" :
                                        goodsVOs.get(i).getGoodsAttrPOS().get(i1).getGoodsAttrValues().get(i2).getAttrValuePrice().toString());
                                excelGoodsVO2.setAttrValuePics(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getGoodsAttrValues().get(i2).getAttrValuePics());
                                excelGoodsVO2.setGoodsId(goodsVOs.get(i).getId());
                                excelGoodsVO2.setAttrId(goodsVOs.get(i).getGoodsAttrPOS().get(i1).getId());
                                list1.add(excelGoodsVO2);
                            }
                    }
                }
            }
            //构建表格
            Map<Long, Map<Long, List<ExcelGoodsVO2>>> collect1 =
                    list1.stream().collect(
                            Collectors.groupingBy(ExcelGoodsVO2::getGoodsId,//商品分组
                                    Collectors.groupingBy(ExcelGoodsVO2::getAttrId)));//Attr分组
            int lastRowNum1, lastRowNum11 = 1, lastRowNum2, lastRowNum22 = 1;
            //根据商品+属性聚合
            for (Long aGoodsId : collect1.keySet()) {
                lastRowNum1 = lastRowNum11;//商品
                Map<Long, List<ExcelGoodsVO2>> aGoodsIdMap = collect1.get(aGoodsId);
                for (Long aAttrId : aGoodsIdMap.keySet()) {
                    lastRowNum2 = lastRowNum22;
                    List<ExcelGoodsVO2> excelGoodsVO2s = aGoodsIdMap.get(aAttrId);
                    for (int i = 0; i < excelGoodsVO2s.size(); i++) {
                        XSSFRow row = sheet.createRow(lastRowNum22);
                        lastRowNum11++;
                        lastRowNum22++;
                        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(excelGoodsVO2s.get(i)));
                        for (int i1 = 0; i1 < goodsAttrs.length; i1++) {
                            row.createCell(i1).setCellValue(jsonObject.getString(goodsAttrs[i1]));
                        }
                    }
                    if (!(lastRowNum2 < lastRowNum22 - 1)) {
                        continue;
                    }
                    //合并商品属性
                    sheet.addMergedRegion(new CellRangeAddress(lastRowNum2, //first row (0-based)
                            lastRowNum22 - 1, //last row  (0-based)
                            6, //first column (0-based)
                            6  //last column  (0-based)
                    ));
                }
                //合并goods属性
                if (!(lastRowNum1 < lastRowNum11 - 1)) {
                    continue;
                }
                //合并商品id
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        0, //first column (0-based)
                        0  //last column  (0-based)
                ));
                //合并商品名
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        1, //first column (0-based)
                        1  //last column  (0-based)
                ));
                //合并商品类型
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        2, //first column (0-based)
                        2  //last column  (0-based)
                ));
                //合并商品价格
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        3, //first column (0-based)
                        3  //last column  (0-based)
                ));
                //合并商品图片
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        4, //first column (0-based)
                        4 //last column  (0-based)
                ));
                //合并商品标签
                sheet.addMergedRegion(new CellRangeAddress(lastRowNum1, //first row (0-based)
                        lastRowNum11 - 1, //last row  (0-based)
                        5, //first column (0-based)
                        5  //last column  (0-based)
                ));
            }
            ServletOutputStream outputStream = response.getOutputStream();
            wb.write(outputStream);
        } catch (
                IOException e) {
        }
    }
}
